﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;

namespace Glucometer.ModuleHandler
{
    class TestingModuleHandler : GlucometerModuleHandler
    {
        private int _countProgress = 0;

        //5 MINUTES FOR BLOOD APPLICATION
        public static int BLOOD_APPLYING_TIME_PERIOD = 10 * 1000;

        public static int RESULT_WAITING_TIME_PERIOD = 10 * 1000;

        private static Timer _progressCountingTimer = new Timer(1000);

        public int ProgressLimit = 10;

        public TestingModuleHandler(IHarware hardware, DeviceMemory memory, DeviceSettings setting, DeviceStatus status)
            : base(hardware, memory, setting, status)
        {
            _progressCountingTimer.Elapsed += new ElapsedEventHandler(_progressCountingTimer_Elapsed);

            _progressCountingTimer.AutoReset = true;

            GlucometerModuleHandler.DeviceEnding += new d_EmptyArgument(GlucometerModuleHandler_DeviceEnding);
        }

        void GlucometerModuleHandler_DeviceEnding()
        {
            //IF THE DEVICE IS ENDING THEN STOP THE TESTING PROCESS
            _progressCountingTimer.Stop();

            //SET THE PROGRESS TO -1 TO SIGNAL TO HIDE PROGRESS BAR
            _hardware.ShowProgress(-1);
        }

        void _progressCountingTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            //IF THE PROGRESS LIMIT IS NOT MAX ALLOWED THEN SHOW THE INCREMENTED PROGRESS VALUE LIMIT
            //IN THE SRS ITS MENTIONED 60 SEC SO IT SHOULD BE 60
            if (++_countProgress <= ProgressLimit)
            {
                _hardware.ShowProgress(_countProgress);
            }
            else
            {
                //SET THE ERROR
                GlucometerModuleHandler.setLastError(ErrorCode.TESTING_ERROR, 
                    "The result was not ready in the LIMIT SET TIME.");

                //STOP THE PROGRESS TIMER
                _progressCountingTimer.Stop();

                //END THE DEVICE
                endDevice(EndingType.ERROR, OperationMode.TESTING);
            }
            
            _hardware.ShowDisplay(_countProgress.ToString());
        }

        public override bool doModeValidation(SoftwareEventsType set)
        {
            //CHECK IF THE STRIP IS INSERTED
            //if (_hardware.getStatus(HardwareStatus.TEST_STRIP_INSERTED))
            if(_deviceStatus.testStripInserted)
            {
                //CHECK IF THE INSERTED STRIP IS VALID
                if (_hardware.getStatus(HardwareStatus.IS_VALID_TEST_STRIP))
                {
                    return true;
                }
                else 
                {
                    setLastError(ErrorCode.MODE_VALIDATION_ERROR, "Invalid test strip inserted");
                }
            }
            else { setLastError(ErrorCode.MODE_VALIDATION_ERROR, "Test strip not inserted"); }

            return false;
        }

        public override bool doStatusCheck(SoftwareEventsType set)
        {
            // METER STATUS CHECK
            //if (_hardware.getStatus(HardwareStatus.USB_INSERTED))
            if(_deviceStatus.usbConnected)
            {
                setLastError(ErrorCode.METERSTATUSCHECK_ERROR,"USB still connected in testing mode");
                return false;
            }
            return true;
        }

        public override bool handleEventInMode(SoftwareEventsType set)
        {
            if (set == SoftwareEventsType.STRIP_REMOVED)
            {
                //STOP THE PROGRESS 
                _progressCountingTimer.Stop();
                //SET THE PROGRESS TO -1 TO SIGNAL TO HIDE PROGRESS BAR
                _hardware.ShowProgress(-1);
                //THEN END THE DEVICE VOLUNTARILY
                endDevice(EndingType.VOLUNTARY, OperationMode.TESTING);

                return true;
            }
            else if (set == SoftwareEventsType.SUFFICIENT_BLOOD)
            {
                //IF THERE IS SUFFICIENT BLOOD START TESTING
                _hardware.ShowDisplay("TESTING");
                //SET THE RESULT PROGRESS TO 0
                _countProgress = 0;
                //SET THE IDLE COUNTER TIME PERIOD TO LARGE VALUE 1 HOUR SO IDLE TIMER DOESNOT END THE DEVICE
                restartIdlePeriodCounter(60 * 60 * 1000);
                //START THE PROGRESS
                _progressCountingTimer.Start();

                return true;
            }
            else if (set == SoftwareEventsType.INSUFFICIENT_BLOOD)
            {
                //THIS IS AN ERROR SO SHOW ERROR AND FOLLOW ERROR ENDING PROCEDURE
                GlucometerModuleHandler.setLastError(ErrorCode.INSUFFICIENTBLOOD_ERROR, "Not sufficient blood applied.");
                
                endDevice(EndingType.ERROR, OperationMode.TESTING);

                return true;
            }
            else if (set == SoftwareEventsType.RESULT_READY)
            {
                _progressCountingTimer.Stop();

                //SET THE PROGRESS BAR TO REACH THE MAX PROGRESS LIMIT
                _hardware.ShowProgress(ProgressLimit);

                //SET THE PROGRESS TO -1 TO SIGNAL TO HIDE PROGRESS BAR
                _hardware.ShowProgress(-1);

                //GET THE TEST RESULT IN APPROPRIATE UNIT
                int result = GetTestResult(_settings.TestUnit);

                // STORE THE TEST RESULT IN DEVICE MEMORY
                _deviceMemory.addRecord(new TestRecord(result, _settings.getDateTime(), _settings.TestUnit));

                //DISPLAY THE TEST RESULT
                _hardware.DisplayResult(result, _settings.TestUnit);

                //SET THE IDLE TIME PERIOD COUNTER TO IDLE_TIME_PERIOD
                restartIdlePeriodCounter(IDLE_TIME_INTERVAL);

                return true;
            }

            return false;
        }

        private int GetTestResult(TestUnit tu)
        {
            // GET TEST RESULT BY A RANDOM NUMBER
            Random random = new Random();

            //CONVERT TO APPROPRIATE UNIT
            return TestUnitConverter.Convert(random.Next(0, 999), TestUnit.DL, tu);
        }

        public override void loadMode()
        {
            //RESET THE IDLE PERIOD COUNTER TO BLOOD APPLYING TIME PRIOD
            restartIdlePeriodCounter(BLOOD_APPLYING_TIME_PERIOD);
        }
    }
}